using System.Globalization;
using System.IO;
using System.Web.Mvc;
using System.Web.Routing;
using ExtendedMvc.Common.Diagnostics;

namespace ExtendedMvc.Elements {
	public class Partial<TModel> : PartialBase<Partial<TModel>, TModel> where TModel : class {
		private string _viewName;
		private object _model;
		private ViewDataDictionary _viewData;

		public Partial(IModelViewHelper<TModel> helper, string viewName, object model = null, ViewDataDictionary viewData = null) : base(helper)  {
			Check.Argument.IsNotNullOrEmpty(viewName, "viewName");
			_viewName = viewName;
			_model = model;
			_viewData = viewData;
		}

		public override string ToString() {
			var writer = new StringWriter(CultureInfo.CurrentCulture);
			helper.RenderPartialContent(_viewName, _model, _viewData, writer, ViewEngines.Engines);
			return writer.ToString();
		}
	}

	public class RoutePartial<TModel> : PartialBase<RoutePartial<TModel>, TModel> where TModel : class {
		private string _routeName;
		private string _protocol;
		private string _hostName;
		private RouteValueDictionary _routeValues;

		public RoutePartial(IModelViewHelper<TModel> helper, string routeName, string protocol = null, string hostName = null, object routeValues = null) : base(helper)  {
			_routeName = routeName;
			_protocol = protocol;
			_hostName = hostName;
			_routeValues = (routeValues is RouteValueDictionary ? (routeValues as RouteValueDictionary) : new RouteValueDictionary(routeValues));
		}

		public override string ToString() {
			var writer = new StringWriter(CultureInfo.CurrentCulture);
			helper.RenderPartialContent(_routeName, _protocol, _hostName, _routeValues, writer);
			return writer.ToString();
		}
	}

	public class ActionPartial<TModel> : PartialBase<ActionPartial<TModel>, TModel> where TModel : class {
		private string _actionName;
		private string _controllerName;
		private RouteValueDictionary _routeValues;

		public ActionPartial(IModelViewHelper<TModel> helper, string actionName, string controllerName = null, object routeValues = null) : base(helper) {
			_actionName = actionName;
			_controllerName = controllerName;
			_routeValues = (routeValues is RouteValueDictionary ? (routeValues as RouteValueDictionary) : new RouteValueDictionary(routeValues));
		}

		public override string ToString() {
			var writer = new StringWriter(CultureInfo.CurrentCulture);
			helper.RenderPartialContent(_actionName, _controllerName, _routeValues, writer);
			return writer.ToString();
		}
	}

	public abstract class PartialBase<T, TModel>
		where T : PartialBase<T, TModel>
		where TModel : class {
		private IModelViewHelper<TModel> _helper;

		protected IModelViewHelper<TModel> helper { get { return _helper; } }

		protected PartialBase(IModelViewHelper<TModel> helper) {
			Check.Argument.IsNotNull(helper, "helper");
			_helper = helper;
		}

		public virtual MvcHtmlString Render() {
			return MvcHtmlString.Create(this.ToString());
		}
	}
}